﻿using System;
using System.Globalization;


namespace Teal.Compiler {

    /// <summary>
    /// 包含用于字符判断的工具函数。
    /// </summary>
    public static class Unicode {

        /// <summary>
        /// 判断一个字符是否为空白字符。
        /// </summary>
        /// <param name="ch">要判断的字符。</param>
        /// <returns>如果是，则返回 true 。</returns>
        public static bool isWhiteSpace(int ch) {

            // WhitespaceCharacter:
            //   Any character with unicode class Zs
            //   Horizontal tab character (U+0009)
            //   Vertical tab character (U+000B)
            //   Form feed character (U+000C) 

            switch (ch) {
                case ' ':
                case '\t':
                case '\v':
                case '\f':
                case '\u00A0':

                // BOM 作为空格处理。
                case '\uFEFF':
                case '\uFFFE':
                case '\u001A':
                    return true;
                default:
                    return ch > 255 && CharUnicodeInfo.GetUnicodeCategory((char)ch) == UnicodeCategory.SpaceSeparator;
            }

        }

        /// <summary>
        /// 判断一个字符是否是行尾。
        /// </summary>
        /// <param name="ch">要判断的字符。</param>
        /// <returns>如果是，则返回 true 。</returns>
        public static bool isLineTerminator(int ch) {

            // NewLineCharacter:
            //   Carriage return character (U+000D)
            //   Line feed character (U+000A)
            //   Next line character (U+0085)
            //   Line separator character (U+2028)
            //   Paragraph separator character (U+2029) 

            switch (ch) {
                case '\r':
                case '\n':
                case '\u0085':
                case '\u2028':
                case '\u2029':
                    return true;
                default:
                    return false;
            }

        }

        /// <summary>
        /// 判断一个字符是否是行尾。
        /// </summary>
        /// <param name="ch">要判断的字符。</param>
        /// <returns>如果是，则返回 true 。</returns>
        public static bool isLineTerminatorOrEOF(int ch) {
            return isLineTerminator(ch) || ch == -1;
        }

        /// <summary>
        /// 判断一个字符是否是正则表达式内不换行字符。
        /// </summary>
        /// <param name="ch">要判断的字符。</param>
        /// <returns>如果是，则返回 true 。</returns>
        public static bool isNonTerminator(int ch) {

            // NonTerminator :
            //   SourceCharacter but not LineTerminator

            return !isLineTerminatorOrEOF(ch);
        }

        /// <summary>
        /// 判断一个字符是否是标识符的首字母。
        /// </summary>
        /// <param name="ch">要判断的字符。</param>
        /// <returns>如果是，则返回 true 。</returns>
        public static bool isIdentifierStart(int ch) {

            if ((ch >= 'a' && ch <= 'z')
                || (ch >= 'A' && ch <= 'Z')
                || (ch == '_')) {
                return true;
            }

            if (ch > 128) {

                switch (CharUnicodeInfo.GetUnicodeCategory((char)ch)) {
                    case UnicodeCategory.UppercaseLetter:
                    case UnicodeCategory.LowercaseLetter:
                    case UnicodeCategory.TitlecaseLetter:
                    case UnicodeCategory.ModifierLetter:
                    case UnicodeCategory.OtherLetter:
                        return true;
                }

            }

            return false;
        }

        /// <summary>
        /// 判断一个字符是否是标识符的某个字符。
        /// </summary>
        /// <param name="ch">要判断的字符。</param>
        /// <returns>如果是，则返回 true 。</returns>
        public static bool isIdentifierPart(int ch) {

            // IdentifierPart :
            //   IdentifierStart
            //   UnicodeCombiningMark
            //   UnicodeDigit
            //   UnicodeConnectorPunctuation

            if ((ch >= 'a' && ch <= 'z')
                || (ch >= 'A' && ch <= 'Z')
                || (ch >= '0' && ch <= '9')
                || (ch == '_')) {
                    return true;
            }

            if(ch > 128) {

                switch(CharUnicodeInfo.GetUnicodeCategory((char)ch)){
                    case UnicodeCategory.Format:
                    case UnicodeCategory.ConnectorPunctuation:
                    case UnicodeCategory.NonSpacingMark:
                    case UnicodeCategory.SpacingCombiningMark:
                    case UnicodeCategory.UppercaseLetter:
                    case UnicodeCategory.LowercaseLetter:
                    case UnicodeCategory.TitlecaseLetter:
                    case UnicodeCategory.ModifierLetter:
                    case UnicodeCategory.OtherLetter:
                    case UnicodeCategory.LetterNumber:
                        return true;
                }

            }

            return false;
        }

        /// <summary>
        /// 判断一个字符是否是双字节。
        /// </summary>
        /// <param name="ch"></param>
        /// <returns></returns>
        public static bool isDoubleBytes(int ch) {
            return ch >= 0x80;
        }

        /// <summary>
        /// 判断一个字符是否是字母。
        /// </summary>
        /// <param name="ch">要判断的字符。</param>
        /// <returns>如果是，则返回 true 。</returns>
        public static bool isLetter(int ch) {

            // UnicodeLetter : 
            //   any character in the Unicode categories “Uppercase letter (Lu)”, “Lowercase letter (Ll)”, “Titlecase letter (Lt)”, “Modifier letter (Lm)”, “Other letter (Lo)”, or “Letter number (Nl)”.

            if ((ch >= 'A' && ch <= 'Z')
                || (ch >= 'a' && ch <= 'z')) {
                return true;
            }

            if (ch > 128) {

                switch (CharUnicodeInfo.GetUnicodeCategory((char)ch)) {
                    case UnicodeCategory.UppercaseLetter:
                    case UnicodeCategory.LowercaseLetter:
                    case UnicodeCategory.TitlecaseLetter:
                    case UnicodeCategory.ModifierLetter:
                    case UnicodeCategory.OtherLetter:
                        return true;
                }

            }

            return false;
        }

        /// <summary>
        /// 判断一个字符是否是十六进制数字。
        /// </summary>
        /// <param name="ch">要判断的字符。</param>
        /// <returns>如果是，则返回 true 。</returns>
        public static bool isHexDigit(int ch) {

            // HexDigit :: one of
            //   0 1 2 3 4 5 6 7 8 9 a b ch d e f A B C D E F

            if(isDecimalDigit(ch) ){
                return true;
            }

            //  | 0x20 -> 小写
            ch |= 0x20;

            return ch >= 'a' && ch <= 'f';
        }

        /// <summary>
        /// 判断一个字符是否是十进制数字。
        /// </summary>
        /// <param name="ch">要判断的字符。</param>
        /// <returns>如果是，则返回 true 。</returns>
        public static bool isDecimalDigit(int ch) {

            // DecimalDigit :: one of
            //   0 1 2 3 4 5 6 7 8 9

            return ch >= '0' && ch <= '9';
        }

        /// <summary>
        /// 判断指定的名称是否是标识符。
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public static bool isIdentifier(string name) {
            if (name.Length == 0) {
                return false;
            }
            if (!isIdentifierStart(name[0])) {
                return false;
            }

            for (int i = 1; i < name.Length; i++) {
                if (!isIdentifierPart(name[i])) {
                    return false;
                }
            }

            return true;
        }
    }

}